from fastapi import FastAPI, Request, Form, File, UploadFile, HTTPException
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
import os
import sys
import time
import logging
import json
import shutil

# 将项目根目录添加到 Python 路径，以便导入 backend 模块
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

from backend import config
from backend.video_processing import (
    setup_environment,
    download_video,
    save_uploaded_video,
    process_subtitles,
    burn_subtitles_and_finalize,
    create_video_from_text,
    create_srt_from_text,
    get_available_intros,
    get_available_openings
)
from backend.ai_services import generate_ai_metadata
from backend.youtube_services import upload_to_youtube, get_available_channels
from backend.batch_video_processor import get_global_processor

app = FastAPI()

# 配置模板目录和静态文件目录 (使用绝对路径)
current_dir = os.path.dirname(os.path.abspath(__file__))
templates = Jinja2Templates(directory=os.path.join(current_dir, "templates"))

# 配置静态文件目录
app.mount("/static", StaticFiles(directory=os.path.join(current_dir, "static")), name="static")

@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
    # 获取可用频道列表
    available_channels = get_available_channels()
    # 获取可用视频列表
    available_intros = get_available_intros()
    available_openings = get_available_openings()
    return templates.TemplateResponse("index.html", {
        "request": request, 
        "video_url": config.VIDEO_URL,
        "available_channels": available_channels,
        "available_intros": available_intros,
        "available_openings": available_openings
    })

@app.get("/batch-video", response_class=HTMLResponse)
async def batch_video_page(request: Request):
    """批量视频处理页面"""
    return templates.TemplateResponse("batch_video.html", {
        "request": request
    })

@app.post("/process_video", response_class=HTMLResponse)
async def process_video(
    request: Request,
    video_url: str = Form(""),
    target_language: str = Form("zh"),
    skip_knowledge_card_extraction: bool = Form(False),
    skip_chapter_generation: bool = Form(False),
    skip_summary_and_keywords_extraction: bool = Form(False),
    skip_subtitle_processing: bool = Form(False),
    skip_youtube_upload: bool = Form(False),
    use_original_video_unmodified: bool = Form(False),
    custom_youtube_settings: bool = Form(False),
    custom_title: str = Form(""),
    custom_thumbnail: UploadFile = File(None),
    auto_publish: str = Form("private"),
    auto_upload_immediately: bool = Form(True),
    made_for_kids: bool = Form(False),
    video_mode: str = Form("original"),
    background_image: UploadFile = File(None),
    video_source: str = Form("url"),
    video_file: UploadFile = File(None),
    subtitle_file: UploadFile = File(None),  # 新增：接收字幕文件
    merged_video_path: str = Form(""),  # 来自批量合并的视频路径
    selected_channel: str = Form(""),
    text_input: str = Form(""),
    tts_language: str = Form("zh"),
    tts_speaker: str = Form("female"),
    tts_model: str = Form("chinese"),
    dialogue_mode: str = Form("single"),
    selected_intro: str = Form(""),
    selected_opening: str = Form("")
):
    logging.info(f"收到视频处理请求：源={video_source}, URL={video_url}, 语言={target_language}, 模式={video_mode}, 对话模式={dialogue_mode}")

    # 更新配置
    config.VIDEO_URL = video_url
    config.TARGET_LANGUAGE = target_language
    config.SKIP_KNOWLEDGE_CARD_EXTRACTION = skip_knowledge_card_extraction
    config.SKIP_CHAPTER_GENERATION = skip_chapter_generation
    config.SKIP_SUMMARY_AND_KEYWORDS_EXTRACTION = skip_summary_and_keywords_extraction
    config.SKIP_SUBTITLE_PROCESSING = skip_subtitle_processing
    config.USE_ORIGINAL_VIDEO_UNMODIFIED = use_original_video_unmodified

    # 执行视频处理流程
    try:
        start_time = time.time()
        setup_environment()

        # 统一处理视频源，获取 original_video_path 和 base_name
        original_video_path = None
        base_name = None

        if video_source == "text":
            if not text_input.strip():
                raise HTTPException(status_code=400, detail="文字输入模式需要提供文字内容")
            if not background_image or not background_image.filename:
                raise HTTPException(status_code=400, detail="文字输入模式需要上传背景图片")

            tts_background_path = os.path.join(config.WORK_DIR, "tts_background.jpg")
            with open(tts_background_path, "wb") as f:
                f.write(await background_image.read())

            original_video_path, base_name = create_video_from_text(
                text_input, tts_background_path, tts_language, tts_speaker, tts_model, dialogue_mode
            )
            if not original_video_path:
                raise HTTPException(status_code=500, detail="TTS视频创建失败")

        elif video_source == "upload":
            if merged_video_path and os.path.exists(merged_video_path):
                original_video_path = merged_video_path
                base_name = os.path.splitext(os.path.basename(merged_video_path))[0]
                logging.info(f"使用合并后的视频文件: {original_video_path}")
            elif video_file and video_file.filename:
                original_video_path, base_name = await save_uploaded_video(video_file)
            else:
                raise HTTPException(status_code=400, detail="本地上传模式需要选择视频文件或提供合并视频路径")

            if not original_video_path:
                raise HTTPException(status_code=500, detail="视频文件保存失败")

        elif video_source == "url":
            if not video_url:
                raise HTTPException(status_code=400, detail="在线视频模式需要提供视频链接")
            original_video_path, base_name = download_video(config.VIDEO_URL)
            if not original_video_path:
                raise HTTPException(status_code=500, detail="视频下载失败")
        else:
            raise HTTPException(status_code=400, detail=f"不支持的视频来源类型: {video_source}")

        if use_original_video_unmodified and video_source == "text":
            raise HTTPException(status_code=400, detail="直接使用原视频模式不支持文字合成来源")

        knowledge_cards: list = []
        chapters = ""
        video_summary = ""
        video_keywords: list = []
        final_video_path = original_video_path

        if use_original_video_unmodified:
            logging.info("已选择直接使用原视频，跳过字幕生成、AI元数据与拼接流程。")
        else:
            full_text = ""
            bilingual_srt_path = ""
            original_srt_path = os.path.join(config.WORK_DIR, f"{base_name}_original.srt")

            if subtitle_file and subtitle_file.filename:
                logging.info(f"检测到用户上传了自定义字幕文件: {subtitle_file.filename}")
                bilingual_srt_path = os.path.join(config.WORK_DIR, f"{base_name}_bilingual.srt")
                with open(bilingual_srt_path, "wb") as f:
                    f.write(await subtitle_file.read())

                shutil.copy(bilingual_srt_path, original_srt_path)
                logging.info(f"自定义字幕已保存到: {bilingual_srt_path} 和 {original_srt_path}")

                try:
                    with open(bilingual_srt_path, 'r', encoding='utf-8') as f:
                        lines = f.readlines()
                    full_text = " ".join([
                        line.strip() for line in lines
                        if not line.strip().isdigit() and '-->' not in line and line.strip()
                    ])
                    logging.info("已从上传的SRT文件中提取文本内容")
                except Exception as e:
                    logging.error(f"读取上传的SRT文件失败: {e}")
                    raise HTTPException(status_code=500, detail=f"无法读取上传的SRT文件: {e}")

            elif video_source == "text":
                logging.info("TTS模式，根据输入文本生成字幕")
                import moviepy.editor as mp
                with mp.VideoFileClip(original_video_path) as video_clip:
                    audio_duration = video_clip.duration

                full_text = create_srt_from_text(text_input, audio_duration, original_srt_path)
                bilingual_srt_path = os.path.join(config.WORK_DIR, f"{base_name}_bilingual.srt")
                shutil.copy(original_srt_path, bilingual_srt_path)
                logging.info(f"TTS模式字幕已创建: {bilingual_srt_path}")

            elif not config.SKIP_SUBTITLE_PROCESSING:
                logging.info("未提供自定义字幕，开始自动语音识别流程")
                full_text, bilingual_srt_path = process_subtitles(
                    original_video_path, base_name, config.WORK_DIR
                )
                if not full_text or not bilingual_srt_path:
                    raise HTTPException(status_code=500, detail="自动字幕处理失败")
            else:
                logging.info("用户选择跳过字幕处理，将不执行自动语音识别。")
                bilingual_srt_path = None
                full_text = ""

            if full_text and os.path.exists(original_srt_path) and not (
                config.SKIP_SUBTITLE_PROCESSING and not subtitle_file and video_source != "text"
            ):
                knowledge_cards, chapters, video_summary, video_keywords = generate_ai_metadata(
                    full_text, original_srt_path, original_video_path, skip_chapter_generation
                )
            elif config.SKIP_SUBTITLE_PROCESSING:
                logging.info("已跳过字幕处理，同时跳过 AI 元数据生成。")

            static_background_path = None
            if video_mode == "static" and video_source != "text":
                if background_image and background_image.filename:
                    static_background_path = os.path.join(config.WORK_DIR, f"{base_name}_background.jpg")
                    with open(static_background_path, "wb") as f:
                        f.write(await background_image.read())
                    logging.info(f"背景图片已保存到: {static_background_path}")
                else:
                    raise HTTPException(status_code=400, detail="静态背景模式需要上传背景图片")

            output_path = os.path.join(config.WORK_DIR, f"{base_name}_enhanced.mp4")
            burn_subtitles_and_finalize(
                original_video_path,
                bilingual_srt_path,
                knowledge_cards,
                output_path,
                background_image_path=(static_background_path if video_mode == 'static' else None),
                selected_intro=selected_intro,
                selected_opening=selected_opening
            )
            final_video_path = output_path

        # 处理自定义封皮上传
        thumbnail_path = None
        privacy_status = "private"
        if custom_youtube_settings and custom_thumbnail and custom_thumbnail.filename:
            # 保存上传的封皮文件
            thumbnail_path = os.path.join(config.WORK_DIR, f"{base_name}_thumbnail.jpg")
            with open(thumbnail_path, "wb") as f:
                content = await custom_thumbnail.read()
                f.write(content)
            logging.info(f"封皮已保存到: {thumbnail_path}")

        # 可选的YouTube上传
        action_desc = "完成"
        if not skip_youtube_upload:
            # 检查是否立即上传
            if custom_youtube_settings and not auto_upload_immediately:
                logging.info("视频处理完成，但设置为不立即上传。视频已保存到本地。")
                action_desc = "完成，保留在本地待上传"
            else:
                # 准备YouTube上传参数
                privacy_status = auto_publish if custom_youtube_settings else "private"
                kids_setting = made_for_kids if custom_youtube_settings else False
                youtube_params = {
                    "output_path": final_video_path,
                    "base_name": base_name,
                    "chapters": chapters,
                    "video_summary": video_summary,
                    "video_keywords": video_keywords,
                    "custom_title": custom_title if custom_youtube_settings and custom_title.strip() else None,
                    "thumbnail_path": thumbnail_path,
                    "privacy_status": privacy_status,
                    "made_for_kids": kids_setting,
                    "selected_channel": selected_channel
                }
                upload_to_youtube(**youtube_params)
                action_desc = f"完成并已上传({privacy_status})"
        else:
            logging.info("跳过YouTube上传步骤")
            action_desc = "完成，未上传到YouTube"

        end_time = time.time()
        operation_label = "原视频" if use_original_video_unmodified else "视频处理"
        message = f"{operation_label}{action_desc}！总用时: {end_time - start_time:.2f} 秒。"
        logging.info(message)
        return templates.TemplateResponse("index.html", {
            "request": request,
            "message": message,
            "video_url": video_url,
            "available_channels": get_available_channels(),
            "available_intros": get_available_intros(),
            "available_openings": get_available_openings()
        })
    
    except Exception as e:
        logging.error(f"视频处理过程中发生错误: {e}")
        return templates.TemplateResponse("index.html", {
            "request": request, 
            "message": f"处理失败：{str(e)}", 
            "video_url": video_url,
            "available_channels": get_available_channels(),
            "available_intros": get_available_intros(),
            "available_openings": get_available_openings()
        })


# ============================================================================
# 批量视频处理API端点
# ============================================================================

@app.post("/api/batch/scan-folder")
async def scan_video_folder(request: Request):
    """扫描文件夹中的视频文件"""
    try:
        data = await request.json()
        folder_path = data.get("folder_path")
        recursive = data.get("recursive", False)
        
        if not folder_path:
            raise HTTPException(status_code=400, detail="需要提供文件夹路径")
        
        if not os.path.exists(folder_path):
            raise HTTPException(status_code=400, detail="文件夹不存在")
        
        # 使用批量处理器扫描
        processor = get_global_processor()
        scanner = processor.file_scanner
        
        video_files = scanner.scan_folder(folder_path, recursive)
        summary = scanner.get_summary(video_files)
        
        # 分析命名模式
        naming_analysis = processor.smart_sorter.analyze_naming_pattern(video_files)
        
        # 应用推荐的排序方法进行初始排序
        from backend.smart_sorter import SortMethod
        recommended_method_str = naming_analysis.get("recommended_method", "natural")
        try:
            recommended_method = SortMethod(recommended_method_str)
        except ValueError:
            recommended_method = SortMethod.NATURAL
        
        sorted_video_files = processor.smart_sorter.sort_videos(video_files, recommended_method)
        
        return JSONResponse({
            "success": True,
            "video_files": [
                {
                    "filename": f.filename,
                    "path": f.path,
                    "size": f.size,
                    "duration": f.duration,
                    "resolution": f.resolution,
                    "format": f.format,
                    "is_valid": f.is_valid,
                    "error_message": f.error_message
                }
                for f in sorted_video_files
            ],
            "summary": summary,
            "naming_analysis": naming_analysis
        })
    
    except Exception as e:
        logging.error(f"扫描文件夹失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/batch/preview-sort")
async def preview_video_sort(request: Request):
    """预览视频文件排序"""
    try:
        data = await request.json()
        video_files_data = data.get("video_files", [])
        sort_method = data.get("sort_method", "natural")
        
        # 重建VideoFileInfo对象
        from backend.file_scanner import VideoFileInfo
        from datetime import datetime
        
        video_files = []
        for f_data in video_files_data:
            video_file = VideoFileInfo(
                path=f_data["path"],
                filename=f_data["filename"],
                size=f_data["size"],
                duration=f_data["duration"],
                resolution=tuple(f_data["resolution"]),
                fps=f_data.get("fps", 0),
                format=f_data["format"],
                created_time=datetime.now(),  # 简化处理
                modified_time=datetime.now(),
                is_valid=f_data["is_valid"],
                error_message=f_data.get("error_message")
            )
            video_files.append(video_file)
        
        # 获取排序预览
        processor = get_global_processor()
        from backend.smart_sorter import SortMethod
        
        try:
            method = SortMethod(sort_method)
        except ValueError:
            method = SortMethod.NATURAL
        
        preview = processor.smart_sorter.get_sort_preview(video_files, method)
        
        return JSONResponse({
            "success": True,
            "preview": preview
        })
    
    except Exception as e:
        logging.error(f"预览排序失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/batch/start-merge")
async def start_batch_merge(request: Request):
    """开始批量视频合并"""
    try:
        # 处理可能包含文件上传的请求
        form = await request.form()
        
        # 获取基本参数
        video_files_json = form.get("video_files")
        if not video_files_json:
            raise HTTPException(status_code=400, detail="没有提供视频文件")
        
        video_files_data = json.loads(video_files_json)
        output_filename = form.get("output_filename", "merged_video.mp4")
        config_json = form.get("config", "{}")
        config_data = json.loads(config_json)
        
        if not video_files_data:
            raise HTTPException(status_code=400, detail="没有提供视频文件")
        
        # 处理背景音乐文件
        background_music_file = form.get("background_music_file")
        background_music_path = None
        
        if background_music_file and hasattr(background_music_file, 'filename') and background_music_file.filename:
            # 保存背景音乐文件
            import uuid
            file_extension = os.path.splitext(background_music_file.filename)[1]
            background_music_filename = f"bg_music_{uuid.uuid4().hex[:8]}{file_extension}"
            background_music_path = os.path.join(config.WORK_DIR, background_music_filename)
            
            with open(background_music_path, "wb") as f:
                content = await background_music_file.read()
                f.write(content)
            
            logging.info(f"背景音乐文件已保存: {background_music_path}")
            
            # 将背景音乐路径添加到配置中
            config_data["background_music_path"] = background_music_path
        
        # 创建输出路径
        output_path = os.path.join(config.WORK_DIR, output_filename)
        
        # 创建临时文件列表，保留完整的视频文件信息（包括speed）
        import tempfile
        
        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            # 保存完整的视频文件信息而不仅仅是路径
            valid_files_data = [f_data for f_data in video_files_data if f_data.get("is_valid")]
            json.dump(valid_files_data, f)
            temp_file_list = f.name
        
        # 启动批量处理任务
        processor = get_global_processor()
        task_id = processor.create_task_with_file_data(temp_file_list, output_path, config_data)
        
        return JSONResponse({
            "success": True,
            "task_id": task_id,
            "message": "批量合并任务已启动"
        })
    
    except Exception as e:
        logging.error(f"启动批量合并失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/api/batch/task-status/{task_id}")
async def get_task_status(task_id: str):
    """获取任务状态"""
    try:
        processor = get_global_processor()
        status = processor.get_task_status(task_id)
        
        if status is None:
            raise HTTPException(status_code=404, detail="任务不存在")
        
        return JSONResponse({
            "success": True,
            "status": status
        })
    
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"获取任务状态失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/api/batch/task-details/{task_id}")
async def get_task_details(task_id: str):
    """获取任务详细信息"""
    try:
        processor = get_global_processor()
        details = processor.get_task_details(task_id)
        
        if details is None:
            raise HTTPException(status_code=404, detail="任务不存在")
        
        return JSONResponse({
            "success": True,
            "details": details
        })
    
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"获取任务详情失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/batch/cancel-task/{task_id}")
async def cancel_task(task_id: str):
    """取消任务"""
    try:
        processor = get_global_processor()
        success = processor.cancel_task(task_id)
        
        if not success:
            raise HTTPException(status_code=404, detail="任务不存在或无法取消")
        
        return JSONResponse({
            "success": True,
            "message": "任务已取消"
        })
    
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"取消任务失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/api/batch/list-tasks")
async def list_all_tasks():
    """列出所有任务"""
    try:
        processor = get_global_processor()
        tasks = processor.list_tasks()
        
        return JSONResponse({
            "success": True,
            "tasks": tasks
        })
    
    except Exception as e:
        logging.error(f"列出任务失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/api/batch/continue-to-main-flow/{task_id}")
async def continue_to_main_flow(task_id: str):
    """获取合并后的视频路径，准备继续主处理流程"""
    try:
        processor = get_global_processor()
        task_details = processor.get_task_details(task_id)
        
        if not task_details:
            raise HTTPException(status_code=404, detail="任务不存在")
        
        if task_details["status"] != "completed":
            raise HTTPException(status_code=400, detail="任务尚未完成")
        
        output_path = task_details["output_path"]
        if not os.path.exists(output_path):
            raise HTTPException(status_code=400, detail="合并后的视频文件不存在")
        
        # 获取文件信息
        file_size = os.path.getsize(output_path)
        filename = os.path.basename(output_path)
        
        return JSONResponse({
            "success": True,
            "message": "合并完成，准备进入AI处理流程",
            "video_path": output_path,
            "filename": filename,
            "file_size": file_size
        })
    
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"获取合并视频信息失败: {e}")
        raise HTTPException(status_code=500, detail=str(e))
